/**
 * Initiates queries for Contig and Pairs tables
 * Columns for contig pairs table
 * Links columns to database fields (see FilterContigData for Contig table)
 */
package jpave.dataholders;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.Serializable;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import jpave.database.JPaveDBWrapper;
import jpave.query_interface.FieldMapper;
import jpave.query_interface.FieldTab;

import java.sql.Connection;

import assem.RStat;
import util.Debug.ErrorReport;
import util.data_structures.PrefixTree;
import util.methods.*;
import util.ui.CachedTable;

public class QueryData implements Serializable
{		
	private static final boolean debug = false;
	private static final int QUERY_INCREMENT = 50000;
	
	// called by JPaveFraem.addAllContigsTab which is called from openAssembly
	static public QueryData createAllContigsQuery ( GlobalSettings settings, int parentFrameID ) 
	{
		return new QueryData ( QUERY_CONTIGS, settings, parentFrameID );
	}

	// called by JPaveFrame.addAllContigsPairsTab which is called from openAssembly
	static public QueryData createAllContigPairsQuery ( GlobalSettings settings, int parentFrameID ) 
	{
		QueryData data = new QueryData ( QUERY_PAIRS, settings, parentFrameID );			
		return data;
	}

	public QueryData ( int inType, GlobalSettings settings, int parentFrameID ) 
	{ 
		theFilter = new FilterContigData (settings);
		nType = inType;
	}
	
	public boolean isAllContigs ( )
	{
		return nType == QUERY_CONTIGS && theFilter.isAllContigs();
	}

	public boolean isAllContigPairs ( )
	{
    		return nType == QUERY_PAIRS
			&& theFilter.isAllContigs()
			&& !pairsCompareSimilarity 
			&& !pairsCompareBestHit
			&& pairsHSRMinNTLen == 0
    		&& pairsHSRMinNTPercentLen == 0 
    		&& pairsHSRMinAALen == 0
    		&& pairsHSRMinAAPercentLen == 0.0
			&& pairsOLPMinNTLen == 0
    		&& pairsOLPMinNTPercentLen == 0 
    		&& pairsOLPMinAALen == 0
    		&& pairsOLPMinAAPercentLen == 0.0
    		&& pairsOLPMinAAPercentID == 0.0
    		&& pairsOLPMinNTPercentID == 0.0
    		&& pairsHSRMinAAPercentID == 0.0
    		&& pairsHSRMinNTPercentID == 0.0;
	}
	
	/**
	 * Loads the list of contigs and/or contig pairs that result from the input query
	 * called from JPaveFrame.handleImmediateQuery and handleLoadQuery
	 */
    public int loadQueryResults ( SessionData session, FieldTab fTab, FieldMapper mapper, String [] contigIDs, String strCacheFileName ) 
    throws Exception
    {	
    		int count = 0; 
    	
    		resetFieldIndexes ( );
    	
	     String strAssemblyIDs;
	     String strSQL = null;
	     
		nContig1Idx = mapper.getVisibleIndexForID(FilterContigData.CONTIG_ID_FIELD);
		
		strAssemblyIDs = session.getAssemblyIDList( false ); // TODO
			
		strSQL = theFilter.getContigListSQL(mapper, fTab, contigIDs, strAssemblyIDs);

			count = runDBQuery2(session,
					strSQL, null, null,
					mapper, fTab, strCacheFileName);

     	return count;
    }

	/**
	 * Loads the list of contigs and/or contig pairs that result from the input query
	 * called from JPaveFrame.handleImmediateQuery and handleLoadQuery
	 */
    public int loadQueryResults ( SessionData session, FieldTab fTab, FieldMapper mapper, String strCacheFileName ) 
    throws Exception
    {	
    		int count = 0; 
    	
    		resetFieldIndexes ( );
    	
	     String strAssemblyIDs;
	     String strSQL = null;
	     
	     if (nType == QUERY_CONTIGS) {
		     PrefixTree filterInclude = theFilter.getIncludeFilterList(session);
		     PrefixTree filterExclude = theFilter.getExcludeFilterList(session);

		        //Check if results are redundant
		     if(filterInclude != null && filterInclude.size() > 0)
		        	filterExclude = null;
		        				
			nContig1Idx = mapper.getVisibleIndexForID(FilterContigData.CONTIG_ID_FIELD);
			
			strAssemblyIDs = session.getAssemblyIDList( false ); // TODO
			
			strSQL = theFilter.getContigListSQL(mapper, fTab, strAssemblyIDs);

			count = runDBQuery2(session,
					strSQL, filterInclude, filterExclude,
					mapper, fTab, strCacheFileName);
	      }
	      else {
			nContig1Idx = mapper.getVisibleIndexForID(FIELD_ID_CONTIG_1);
			
	        strAssemblyIDs = session.getAssemblyIDList( true );
	        
	        strSQL = getPairListSQL( strAssemblyIDs );

	    		count = runDBQuery2(session,
		    		strSQL, null, null,
		    		mapper, fTab, strCacheFileName);	
	    }   

     	return count;
    }

    // FIXME CachedTable - saved in user's .jpave directory, does it get cleaned up?
    // called at startup -  and everytime "Refresh columns" or "Show Filter"
    private int runDBQuery2 ( 	SessionData session, String strQuery,
								PrefixTree filterIncludeContigs, PrefixTree filterExcludeContigs, 
								FieldMapper mapper, FieldTab fTab, String strCacheFileName) 
    throws Exception
	{    	
    		int count = 0; 

		Statement stmt = null;
		Connection conn = null; 

		if (StringHelpers.isEmpty(strQuery)) {
			System.err.println("Error: the query produced no results");
			return 0; // Null query
		}
		BufferedWriter p = null;
		if (!StringHelpers.isEmpty(strCacheFileName))
			p = new BufferedWriter(new FileWriter(strCacheFileName));
		
		if (p == null) { // CAS error from web if permissions are wrong
			System.err.println("Error: your permissions do not allow writing a file");
			return 0;
		}
		// Load the filter list of contigs
		try {
			conn = session.getConnection();
			stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);		
				// supposed to prevent memory hogging on large query
			stmt.setFetchSize(Integer.MIN_VALUE);

			int pos = 0;
			boolean readMoreData = true;
				
			RStat rStatCalcInc = null;
			int [] libCounts = null; 
			if(theFilter.getIncludeLibs() != null && theFilter.getIncludeLibs().length > 0) {
				libCounts = JPaveDBWrapper.getLibCounts(conn, theFilter.getIncludeLibs());
				rStatCalcInc = new RStat(libCounts);
			}

			while(readMoreData) {
				readMoreData = false;
				// XXX Executes Query here!
				ResultSet rset = stmt.executeQuery(strQuery + " LIMIT " + 
							pos + ", " + QUERY_INCREMENT);

				pos += QUERY_INCREMENT;

				while (rset.next()) {
						readMoreData = true;
	
						// Create the output row
						Object[] row = null;
		
						if (nType == QUERY_CONTIGS) {
							row = createContigObjectArray(rset, fTab, 
									filterIncludeContigs, filterExcludeContigs,
									mapper, count+1, rStatCalcInc, session);
						}
						else
							row = createPairObjectArray(rset, mapper, count+1 );
								
						// If passed filter, add to output list
						if (row != null) {
							count++; 
							if (p != null) {
								for (int i = 0;  i < row.length;  i++) {
									if (row[i] != null) {
										String s = row[i].toString();
										p.write(s, 0, s.length());
									}
									p.write(CachedTable.CACHE_FILE_DELIMITER, 0, 1);
								}
								p.newLine();
							}
						}
					}
				}
		} catch (Exception e) {
			ErrorReport.reportError(e, "sTCW Internal Error running query");
		} finally {
			if (p != null) p.close();
			if (stmt != null) stmt.close();
			if (conn != null) conn.close();
		}
		
		return count; 
	}
    /**
     * Creates a row for the pair list 
     */
	public Object[] createPairObjectArray ( ResultSet rset, 
											FieldMapper mapper,
											int nRecordID ) throws Exception
	{	
	    	Object [] array = mapper.getPairObjFromDB( rset, nRecordID, theFilter, null);		
			return array;
	}
    
    /**
     * Creates a row for the contig list 
     */
	public Object[] createContigObjectArray ( 	ResultSet rset, FieldTab fTab, 
												PrefixTree filterIncludeContigs, 
												PrefixTree filterExcludeContigs, 
												FieldMapper mapper, 
												int nRecordID,
												RStat incRStat, SessionData session) throws Exception
	{
		String strContig =  rset.getString( nContig1Idx + 1 ); // TODO column index out of range (0 > 12)
		
		// If we have an exclude filter, make sure neither contig is in the list
		if ( filterExcludeContigs != null && 
				filterExcludeContigs.findExactObj( strContig ) != null )
			return null;
		
		// If we have a include filter, make sure both contig pass 
		// or include related is selected and at least one passed
		if ( filterIncludeContigs != null &&
				filterIncludeContigs.findExactObj( strContig ) == null )
			return null;
		
		Object[] array = mapper.getContigObjFromDB( rset, nRecordID, theFilter, fTab, incRStat, session );

		return array;
	}
	
	/**
	 * XXX Methods for defining Pairs columns and mapping to database
	 * the database is queried for all columns and some filters are performed at the time of query
	 */
	private String getPairListSQL ( String strGroupIDList )         
	{	
		if (nType != QUERY_PAIRS) return null;

        String sqlHSRMinNT = 	" ( NT_hsr_len >= " + pairsHSRMinNTLen + 
        						" AND NT_hsr_ratio >= " + pairsHSRMinNTPercentLen + " ) "; 
        String sqlHSRMinAA = 	" (AA_hsr_len  >= " + pairsHSRMinAALen + 
        						" AND AA_hsr_ratio >= " + pairsHSRMinAAPercentLen + " ) "; 

        String sqlHSRPred = 	" ( ( " + sqlHSRMinNT + " ) AND ( " + sqlHSRMinAA + ") ) ";
 
        String sqlOLPMinNT = 	" ( NT_olp_len >= " + pairsOLPMinNTLen + 
								" AND NT_olp_ratio >= " + pairsOLPMinNTPercentLen + " ) "; 
        String sqlOLPMinAA =	" (AA_olp_len  >= " + pairsOLPMinAALen + 
								" AND AA_olp_ratio >= " + pairsOLPMinAAPercentLen + " ) "; 

		String sqlOLPPred = 	" ( ( " + sqlOLPMinNT + " ) AND ( " + sqlOLPMinAA + ") ) ";

        String sqlOLPMinNTID = 	" ( AA_hsr_pid >= " + pairsHSRMinAAPercentID + 
								" AND nt_hsr_pid >= " + pairsHSRMinNTPercentID + " ) "; 
        String sqlOLPMinAAID =	" (AA_olp_pid  >= " + pairsOLPMinAAPercentID + 
								" AND nt_olp_pid >= " + pairsOLPMinNTPercentID + " ) "; 

        String sqlOLPPredID = 	" ( ( " + sqlOLPMinNTID + " ) AND ( " + sqlOLPMinAAID + ") ) ";

		String sqlPred = "(" + sqlHSRPred + " AND " + sqlOLPPred + " AND " + sqlOLPPredID + ")";
		String sqlPairsBestHit = " in_uniprot_set=1 AND " +
				" ( ( SELECT bestmatchid FROM contig WHERE contig1 = contigid ) = " +
				" ( SELECT bestmatchid FROM contig WHERE contig2 = contigid ) ) ";
            
        // Combine all of the conditions into a single predicate
		if ( pairsCompareBestHit )
			sqlPred = " ( ( " + sqlPred + " ) AND ( " + sqlPairsBestHit + ") ) ";
 
        String sqlSubQ = "SELECT " +
        			"(NT_hsr_score/NT_hsr_len) as nt_hsr_pid, " +
					"(AA_hsr_score/AA_hsr_len) as AA_hsr_pid, " +
	      			"(NT_olp_score/NT_olp_len) as nt_olp_pid, " +
					"(AA_olp_score/AA_olp_len) as AA_olp_pid, " +
					"contig1, contig2, " +
					"NT_hsr_ratio, NT_hsr_score, NT_hsr_len, NT_olp_ratio, NT_olp_score, NT_olp_len, " +
					"AA_hsr_ratio, AA_hsr_score, AA_hsr_len, AA_olp_ratio, AA_olp_score, AA_olp_len, " +
					" in_uniprot_set, in_self_blast_set, in_translated_self_blast, " +
					" cnt_shared_hits, e_value, shared_hitID " + 
        			" FROM pja_pairwise " +
        			" WHERE assembly_id IN " + strGroupIDList; 
 
         String sql = "SELECT align_and_c1.*, " +
         				"c2.numclones as ests2, c2.consensus_bases as length2, c2.bestmatchid as bestmatchid2 " +
            		 	" FROM contig AS c2 " +
            		 	" RIGHT OUTER JOIN " +
            		  "( SELECT align.*, " +
            		  		"c1.numclones as ests1, c1.consensus_bases as length1, c1.bestmatchid as bestmatchid1 " +
	           		" FROM contig AS c1 " +
	           		" RIGHT OUTER JOIN ( " + sqlSubQ + " ) AS align " +
	           		" ON c1.contigid = align.contig1 " +
			        " WHERE " + sqlPred + " ) AS align_and_c1 " +
			        " ON c2.contigid = align_and_c1.contig2 ";
         return sql;
       
	}

	final static public int RECORD_NUM_FIELD = 900;
	final static public int FIELD_ID_CONTIG_1 	= 1000;
	final static public int FIELD_ID_CONTIG_2 	= 1001;
	final static public int FIELD_ID_ESTS_1 	= 1002;
	final static public int FIELD_ID_ESTS_2 	= 1003;
	final static public int FIELD_ID_LENGTH_1 	= 1004;
	final static public int FIELD_ID_LENGTH_2 	= 1005;
	final static public int FIELD_ID_BESTHIT_1 	= 1006;
	final static public int FIELD_ID_BESTHIT_2 	= 1007;
	
	final static public int FIELD_SHARED_HIT_CNT = 1050;
    final static public int FIELD_SHARED_E_VALUE = 1051;
	final static public int FIELD_HAS_SELFBLAST =  1052;
	final static public int FIELD_HAS_TSELFBLAST =  1053;
	
	final static public int FIELD_ID_NT_HSR_PID 	= 2000;
	final static public int FIELD_ID_NT_HSR_LEN 	= 2001;
	final static public int FIELD_ID_NT_HSR_RATIO 	= 2002;	
	final static public int FIELD_ID_AA_HSR_PID 	= 2003;
	final static public int FIELD_ID_AA_HSR_LEN 	= 2004;
	final static public int FIELD_ID_AA_HSR_RATIO 	= 2005;
	
	final static public int FIELD_ID_NT_OLAP_PID 	= 2006;
	final static public int FIELD_ID_NT_OLAP_LEN 	= 2007;
	final static public int FIELD_ID_NT_OLAP_RATIO 	= 2008;	
	final static public int FIELD_ID_AA_OLAP_PID 	= 2009;
	final static public int FIELD_ID_AA_OLAP_LEN 	= 2010;
	final static public int FIELD_ID_AA_OLAP_RATIO 	= 2011;
	
    // Don't use a group names already used by Contig Columns (e.g. General)
    // if you change, also change in FieldTab.createUIFromFields
    final static public String GROUP_NAME_PAIR = "Sequence information";
    final static public String GROUP_DESC_PAIR = "Information about the sequences in a pair.";
    
    final static public String GROUP_NAME_BLAST =  "Blast results for the pair";
    final static public String GROUP_DESC_BLAST =  "Blast evalue for pair.";
   
    final static public String GROUP_NAME_HSR =  "Highest score region (HSR)";
    final static public String GROUP_DESC_HSR =  "Longest region of minimal error from dynamic programming.";
     
    final static public String GROUP_NAME_OLAP = "Total overlap";
    final static public String GROUP_DESC_OLAP = "The total overlap between the pair from dynamic programming.";
 
	/**
	 * Called from JPaveFrame.getContigPairListFields
	 * and jPaveFrame.openAssembly.actionPerformed
	 * Defined here, SQL generated in getPairListSQL above
	 */
    static public FieldMapper createContigPairFieldMapper ( )
    {
        FieldMapper mapper = new FieldMapper (null, null, null);
        
        // General
        mapper.addRecordNumField ( RECORD_NUM_FIELD, "Pair #", 
        		GROUP_NAME_PAIR, GROUP_DESC_PAIR, "The index of the query result." );
        
        mapper.addStringField( FIELD_ID_CONTIG_1, "Seq ID 1", null, "contig1", 
        		GROUP_NAME_PAIR, GROUP_DESC_PAIR, 
        		"Identifier for the first sequence in the comparison." );
        mapper.addStringField( FIELD_ID_CONTIG_2, "Seq ID 2", null, "contig2", 
        		GROUP_NAME_PAIR, GROUP_DESC_PAIR, 
        		"Identifier for the second sequence in the comparison." );
        
        mapper.addIntField( FIELD_ID_ESTS_1, "#Align 1", null, "ests1", 
        		GROUP_NAME_PAIR, GROUP_DESC_PAIR, 
        		"Number of aligned reads to the first consensus sequence." ); 
        mapper.addIntField( FIELD_ID_ESTS_2, "#Align 2", null, "ests2", 
        		GROUP_NAME_PAIR, GROUP_DESC_PAIR, 
        		"Number of aligned reads in the second consensus sequence." ); 
        
        mapper.addIntField( FIELD_ID_LENGTH_1, "Length 1", null, "length1", 
        		GROUP_NAME_PAIR, GROUP_DESC_PAIR, 
        		"Length of first sequence." ); 
        mapper.addIntField( FIELD_ID_LENGTH_2, "Length 2", null, "length2", 
        		GROUP_NAME_PAIR, GROUP_DESC_PAIR, 
        		"Length of second sequence." ); 
        
        mapper.addStringField( FIELD_ID_BESTHIT_1 , "BestHit 1", null, "bestmatchid1", 
        		GROUP_NAME_PAIR, GROUP_DESC_PAIR, 
        		"Best UniProt or Nucleotide hit for the first sequence." ); 
        mapper.addStringField( FIELD_ID_BESTHIT_2 , "BestHit 2", null, "bestmatchid2", 
        		GROUP_NAME_PAIR, GROUP_DESC_PAIR, 
        		"Best UniProt or Nucleotide hit for the second sequence." ); 
        
        // BLAST
        /** CAS 4/24/13 doesn't have a value
        mapper.addIntField( FIELD_SHARED_HIT_CNT, "#Shared Hits", null, "cnt_shared_hits", 
        		GROUP_NAME_BLAST, GROUP_DESC_BLAST, 
        		"Number of shared DB hits that overlap both sequences." ); 
        	**/
        mapper.addFloatField( FIELD_SHARED_E_VALUE, "Blast E-value", null, "e_value", 
        		GROUP_NAME_BLAST, GROUP_DESC_BLAST, 
        		"Blast e-value from selfblast." ); 
        
        // HSR
        String nt_hsr_pid = "(NT_hsr_score/NT_hsr_len)"; 
        mapper.addPercentField( FIELD_ID_NT_HSR_PID, "NT HSR %ID", null, null, 
        		GROUP_NAME_HSR, GROUP_DESC_HSR, 
        		"Percent identity of the NT HSR." );  
        mapper.setFieldSubQuery( FIELD_ID_NT_HSR_PID, "nt_hsr_pid", nt_hsr_pid);
        
        mapper.addIntField( FIELD_ID_NT_HSR_LEN, "NT HSR Len", null, "NT_hsr_len", 
        		GROUP_NAME_HSR, GROUP_DESC_HSR, 
        		"Number of bases in the NT HSR." );   
        
        mapper.addPercentField( FIELD_ID_NT_HSR_RATIO, "NT HSR %Len", null, "NT_hsr_ratio", 
        		GROUP_NAME_HSR, GROUP_DESC_HSR, 
        		"Lenght of HSR divided by shortest of the two sequences." );
               
        String aa_hsr_pid = "(AA_hsr_score/AA_hsr_len)"; 
        mapper.addPercentField( FIELD_ID_AA_HSR_PID, "AA HSR %ID", null, null, 
        		GROUP_NAME_HSR, GROUP_DESC_HSR, 
        		"Percent identity of the AA HSR." );
        mapper.setFieldSubQuery( FIELD_ID_AA_HSR_PID, "aa_hsr_pid", aa_hsr_pid);
        
        mapper.addIntField( FIELD_ID_AA_HSR_LEN, "AA HSR Len", null, "AA_hsr_len", 
        		GROUP_NAME_HSR, GROUP_DESC_HSR, 
        		"Number of amino acids in the AA HSR." );    
 
        mapper.addPercentField( FIELD_ID_AA_HSR_RATIO, "AA HSR %Len", null, "AA_hsr_ratio", 
        		GROUP_NAME_HSR, GROUP_DESC_HSR, 
        		"Length of the HSR divided by the shortest of the two sequences." );
        
        // OLAP   
        String nt_olp_pid = "(NT_olp_score/NT_olp_score)"; 
        mapper.addPercentField( FIELD_ID_NT_OLAP_PID, "NT OLP %ID", null, null, 
        		GROUP_NAME_OLAP, GROUP_DESC_OLAP, 
        		"Percent identity in the NT overlap." );  
        mapper.setFieldSubQuery( FIELD_ID_NT_OLAP_PID, "nt_olp_pid", nt_olp_pid);
        
        mapper.addIntField( FIELD_ID_NT_OLAP_LEN, "NT OLP Len", null, "NT_olp_len", 
        		GROUP_NAME_OLAP, GROUP_DESC_OLAP, 
        		"Number of bases in the NT overlap." );   
        
        mapper.addPercentField( FIELD_ID_NT_OLAP_RATIO, "NT OLP %Len", null, "NT_olp_ratio", 
        		GROUP_NAME_OLAP, GROUP_DESC_OLAP, 
        		"Overlap length divided by the shortest of sequences." ); 
        
        String aa_olp_pid = "(AA_olp_score/AA_olp_len)";
        mapper.addPercentField( FIELD_ID_AA_OLAP_PID, "AA OLP %ID", null, null, 
        		GROUP_NAME_OLAP, GROUP_DESC_OLAP, 
        		"Percent identity in the AA overlap." );
        mapper.setFieldSubQuery( FIELD_ID_AA_OLAP_PID, "aa_olp_pid", aa_olp_pid);      

        mapper.addIntField( FIELD_ID_AA_OLAP_LEN, "AA OLP Len", null, "AA_olp_len", 
        		GROUP_NAME_OLAP, GROUP_DESC_OLAP, 
        		"Number of amino acids in the AA overlap." ); 
        
        mapper.addPercentField( FIELD_ID_AA_OLAP_RATIO, "AA OLP %Len", null, "aa_olp_ratio", 
        		GROUP_NAME_OLAP, GROUP_DESC_OLAP, 
        		"Overlap length divided by the shortest of sequences." );
        
        mapper.setDefaultFieldIDs ( new int [] { 	RECORD_NUM_FIELD,
        			FIELD_ID_CONTIG_1, FIELD_ID_CONTIG_2, 
        			FIELD_ID_NT_HSR_PID, FIELD_ID_NT_HSR_LEN,
        			FIELD_ID_AA_HSR_PID, FIELD_ID_AA_HSR_LEN } );
        
        mapper.setFieldRequired( RECORD_NUM_FIELD );
        mapper.setFieldRequired( FIELD_ID_CONTIG_1 );
        mapper.setFieldRequired( FIELD_ID_CONTIG_2 );
        return mapper;
    }
 
	public void clear()
	{
		if(theFilter != null) theFilter.clear();
	}
	
	/************ temporary variables ******************/
	private void resetFieldIndexes ( )
	{
		nContig1Idx = -1;
	}
	
	transient private int nContig1Idx = -1;
	
	public final static int QUERY_CONTIGS	 		= 0;
	public final static int QUERY_PAIRS 			= 1;
	
	public final static int QUERY_AND = FilterContigData.FILTER_AND;
	public final static int QUERY_OR = FilterContigData.FILTER_OR;
	
    private static final long serialVersionUID = 1;
    
	public int getType() { return nType; }
	public void setType(int type) { nType = type; }
	
	
	// Filter Pairs Query values
	public boolean isPairsCompareSimilarity() { return pairsCompareSimilarity; }
	public void setPairsCompareSimilarity(boolean b) { 
		this.pairsCompareSimilarity = b; }
	
	public int getPairsHSRMinNTLen() { return pairsHSRMinNTLen; }
	public void setPairsHSRMinNTLen(int x) { 
		this.pairsHSRMinNTLen = x; } 
	
	public double getPairsHSRMinNTPercentLen() {  return pairsHSRMinNTPercentLen; } 
	public void setPairsHSRMinNTPercentLen(double x) { 
		this.pairsHSRMinNTPercentLen = x; } 
	
	public int getPairsHSRMinAALen() { return pairsHSRMinAALen; }
	public void setPairsHSRMinAALen(int x) { 
		this.pairsHSRMinAALen = x; }
	
	public double getPairsHSRMinAAPercentLen() { return pairsHSRMinAAPercentLen; } 
	public void setPairsHSRMinAAPercentLen(double x) { 
		this.pairsHSRMinAAPercentLen = x; } 
	
	public double getPairsHSRMinAAPercentID() { return pairsHSRMinAAPercentID; } 
	public void setPairsHSRMinAAPercentID(double x) { 
		this.pairsHSRMinAAPercentID = x; } 
	
	public double getPairsHSRMinNTPercentID() { return pairsHSRMinNTPercentID; } 
	public void setPairsHSRMinNTPercentID(double x) { 
		this.pairsHSRMinNTPercentID = x; } 
	
	public int getPairsOLPMinNTLen() { return pairsOLPMinNTLen; }
	public void setPairsOLPMinNTLen(int x) { 
		this.pairsOLPMinNTLen = x; } 
	
	public double getPairsOLPMinNTPercentLen() {  return pairsOLPMinNTPercentLen; } 
	public void setPairsOLPMinNTPercentLen(double x) { 
		this.pairsOLPMinNTPercentLen = x; } 
	
	public int getPairsOLPMinAALen() { return pairsOLPMinAALen; }
	public void setPairsOLPMinAALen(int x) { 
		this.pairsOLPMinAALen = x; }
	
	public double getPairsOLPMinAAPercentLen() { return pairsOLPMinAAPercentLen; } 
	public void setPairsOLPMinAAPercentLen(double x) { 
		this.pairsOLPMinAAPercentLen = x; } 
	
	public double getPairsOLPMinAAPercentID() { return pairsOLPMinAAPercentID; } 
	public void setPairsOLPMinAAPercentID(double x) { 
		this.pairsOLPMinAAPercentID = x; } 
	
	public double getPairsOLPMinNTPercentID() { return pairsOLPMinNTPercentID; } 
	public void setPairsOLPMinNTPercentID(double x) { 
		this.pairsOLPMinNTPercentID = x; } 
	
	public boolean isPairsCompareBestHit() { return pairsCompareBestHit; }
	public void setPairsCompareBestHit(boolean b) { 
		this.pairsCompareBestHit = b; }
	
	public void setContigFilter ( FilterContigData inFilter ) {theFilter = inFilter;}
	public FilterContigData getContigFilter ( ) { return theFilter; }	

	public boolean isFilterBothMustPass() { return filterBothMustPass; }
	public void setFilterBothMustPass(boolean filterIncludeRelated) { 
		this.filterBothMustPass = filterIncludeRelated; }
	
	// General type of query
	private int nType = QUERY_CONTIGS; 
	private FilterContigData theFilter = null;
	private boolean filterBothMustPass = false;
	
	/*********** homology thresholds ***********/
	// The thresholds for nucleotide identity/amino acid similarity for homologs
	private boolean pairsCompareSimilarity = false; 
	private double pairsHSRMinAAPercentID = 0.0;
	private double pairsHSRMinNTPercentID = 0.0;
	private int pairsHSRMinNTLen = 0;
	private double pairsHSRMinNTPercentLen = 0; 
	private int pairsHSRMinAALen = 0;
	private double pairsHSRMinAAPercentLen = 0.0;
	private double pairsOLPMinAAPercentID = 0.0;
	private double pairsOLPMinNTPercentID = 0.0;
	private int pairsOLPMinNTLen = 0;
	private double pairsOLPMinNTPercentLen = 0; 
	private int pairsOLPMinAALen = 0;
	private double pairsOLPMinAAPercentLen = 0.0;
	private boolean pairsCompareBestHit = false;
}
